#pragma once

#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <type_traits>
#include <chrono>

namespace AsyncThread {
	/**
	 * @class ThreadPool
	 * @brief 线程池类，用于管理一组工作线程并执行提交的任务
	 *
	 * 支持批量任务提交和结果获取，线程安全，使用C++20标准
	 */
	class ThreadPool {
	public:
		/**
		 * @brief 构造函数，创建指定数量的工作线程
		 * @param numThreads 线程池中工作线程的数量
		 * @throws std::runtime_error 如果线程创建失败
		 */
		explicit ThreadPool(size_t numThreads = std::thread::hardware_concurrency()) : mStop(false) {
			try {

				if (numThreads == 0) {
					numThreads = 1; // 至少保留 1 个线程
				}

				mWorkers.reserve(numThreads);
				for (size_t i = 0; i < numThreads; ++i) {
					mWorkers.emplace_back(&ThreadPool::WorkerThread, this);
				}
			}
			catch (...) {
				Stop();
				throw;
			}
		}

		// 禁止拷贝和移动
		ThreadPool(const ThreadPool&) = delete;
		ThreadPool& operator=(const ThreadPool&) = delete;
		ThreadPool(ThreadPool&&) = delete;
		ThreadPool& operator=(ThreadPool&&) = delete;

		/**
		 * @brief 析构函数，停止线程池并等待所有线程完成
		 */
		~ThreadPool() {
			Stop();
		}

		/**
		 * @brief 向线程池提交单个任务
		 * @tparam F 可调用对象类型
		 * @tparam Args 参数类型
		 * @param f 可调用对象
		 * @param args 调用参数
		 * @return std::future<result_of_t<F(Args...)>> 用于获取任务结果的future对象
		 * @throws std::runtime_error 如果线程池已停止
		 */
		template <class F, class... Args>
		auto Enqueue(F&& f, Args&&... args)
			-> std::future<std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>> {
			using return_type = std::invoke_result_t<std::decay_t<F>, std::decay_t<Args>...>;

			auto task = std::make_shared<std::packaged_task<return_type()>>(
				[func = std::forward<F>(f), ...args = std::forward<Args>(args)]() mutable {
					return func(std::forward<Args>(args)...);
				}
			);

			std::future<return_type> res = task->get_future();

			{
				std::unique_lock lock(mQueueMutex);
				if (mStop) {
					throw std::runtime_error("Enqueue on stopped ThreadPool");
				}
				mTasks.emplace([task = std::move(task)]() { (*task)(); });
			}

			mCondition.notify_one();
			return res;
		}

		/**
		 * @brief 批量提交任务到线程池
		 * @tparam F 可调用对象类型
		 * @tparam Args 参数类型
		 * @param tasks 任务列表，每个任务是一个pair<F, Args...>
		 * @return std::vector<std::future<result_of_t<F(Args...)>>> 包含所有任务future的vector
		 * @throws std::runtime_error 如果线程池已停止
		 */
		template <class F, class... Args>
		auto EnqueueBatch(std::vector<std::pair<F, std::tuple<Args...>>> tasks)
			-> std::vector<std::future<std::invoke_result_t<F, Args...>>> {
			using return_type = std::invoke_result_t<F, Args...>;
			std::vector<std::future<return_type>> futures;
			futures.reserve(tasks.size());

			{
				std::unique_lock lock(mQueueMutex);
				if (mStop) {
					throw std::runtime_error("EnqueueBatch on stopped ThreadPool");
				}

				for (auto& task : tasks) {
					auto packaged_task = std::make_shared<std::packaged_task<return_type()>>(
						[func = std::move(task.first), args = std::move(task.second)]() mutable {
							return std::apply(func, args);
						}
					);

					futures.emplace_back(packaged_task->get_future());
					mTasks.emplace([task = std::move(packaged_task)]() { (*task)(); });
				}
			}

			mCondition.notify_all();
			return futures;
		}

		/**
		 * @brief 获取线程池中工作线程的数量
		 * @return size_t 线程数量
		 */
		size_t GetThreadCount() const noexcept {
			return mWorkers.size();
		}

	private:
		void WorkerThread() {
			for (;;) {
				std::function<void()> task;

				{
					std::unique_lock lock(mQueueMutex);
					mCondition.wait(lock, [this] { return mStop || !mTasks.empty(); });

					if (mStop && mTasks.empty()) {
#pragma warning(push)
#pragma warning(disable: 26115)
						return;
#pragma warning(pop)
					}

					task = std::move(mTasks.front());
					mTasks.pop();
				}

				try {
					// 执行任务，function 对象可以捕获异常
					task();
				}
				catch (...) {
					// 捕获任务中的异常，防止线程退出
				}
			}
		}

		void Stop() noexcept {
			{
				std::unique_lock lock(mQueueMutex);
				if (mStop) return;
				mStop = true;
			}

			mCondition.notify_all();

			for (auto& worker : mWorkers) {
				if (worker.joinable()) {
					worker.join();
				}
			}
		}

		std::vector<std::thread> mWorkers;
		std::queue<std::function<void()>> mTasks;
		mutable std::mutex mQueueMutex;
		std::condition_variable mCondition;
		bool mStop;
	};
}